#include "ds18b20.h"
#include "gpio.h"

#include "stdio.h"

//////////////////////////////////////////////////////////////////////////////////	 
//本程序只供学习使用，未经作者许可，不得用于其它任何用途
//ALIENTEK战舰STM32开发板
//DS18B20驱动代码
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2012/9/12
//版本：V1.0
//版权所有，盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2009-2019
//All rights reserved									  
//////////////////////////////////////////////////////////////////////////////////
//#define DS18B20_DQ_OUT_L   HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET)
//#define DS18B20_DQ_OUT_H   HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET)

//#define DS18B20_DQ_IN HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4)

#define DS18B20_DQ_OUT_L   HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15, GPIO_PIN_RESET)
#define DS18B20_DQ_OUT_H   HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15, GPIO_PIN_SET)

#define DS18B20_DQ_IN HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_15)

#if 0
static u8  fac_us=0;							//us延时倍乘数	
void delay_us(unsigned int nus)
{		
	unsigned int temp;	    	 
	SysTick->LOAD=nus*fac_us; 					//时间加载	  		 
	SysTick->VAL=0x00;        					//清空计数器
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;	//开始倒数	  
	do
	{
		temp=SysTick->CTRL;
	}while((temp&0x01)&&!(temp&(1<<16)));		//等待时间到达   
	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;	//关闭计数器
	SysTick->VAL =0X00;      					 //清空计数器	 
}
#else 
void delay_us(unsigned int us)
{
	unsigned int i,j;
	for(i=0;i<us;i++)
	{
////	 __ASM("NOP");
////	 asm("NOP");
////	 asm("NOP");

// 支持 2~6 读写1302数据。
		
//		for(j=0;j<2;j++);
		
	//	支持 6~22 读写1302数据。
		//for(j=0;j<12;j++);
		for(j=0;j<10;j++);
	}
}

#endif

//HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);

void DS18B20_IO_OUT()
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};

	  /* GPIO Ports Clock Enable */
//	  __HAL_RCC_GPIOA_CLK_ENABLE();
	__HAL_RCC_GPIOB_CLK_ENABLE();

	  /*Configure GPIO pin : PA4 */
//	  GPIO_InitStruct.Pin = GPIO_PIN_4;
//	  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
//	   GPIO_InitStruct.Pull = GPIO_PULLUP;
//	   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
//	   HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
	
		GPIO_InitStruct.Pin = GPIO_PIN_15;
	  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	   GPIO_InitStruct.Pull = GPIO_PULLUP;
	   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
	   HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

}

void DS18B20_IO_IN(void)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};

	  /* GPIO Ports Clock Enable */
	  //__HAL_RCC_GPIOA_CLK_ENABLE();
	__HAL_RCC_GPIOB_CLK_ENABLE();

	  /*Configure GPIO pin : PA4 */
//	    GPIO_InitStruct.Pin = GPIO_PIN_4;
//	    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
//	    GPIO_InitStruct.Pull = GPIO_PULLUP;
//	    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
	
	    GPIO_InitStruct.Pin = GPIO_PIN_15;
	    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
	    GPIO_InitStruct.Pull = GPIO_PULLUP;
	    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

}

//复位DS18B20
void DS18B20_Rst(void)	   
{                 
	DS18B20_IO_OUT(); 	//SET PG11 OUTPUT
//    DS18B20_DQ_OUT = 0; 	//拉低DQ
	DS18B20_DQ_OUT_L;

    delay_us(750);    	//拉低750us
//    DS18B20_DQ_OUT=1; 	//DQ=1
    DS18B20_DQ_OUT_H;
	delay_us(15);     	//15US
}


//等待DS18B20的回应
//返回1:未检测到DS18B20的存在
//返回0:存在
u8 DS18B20_Check(void) 	   
{   
	u8 retry=0;
	DS18B20_IO_IN();	//SET PG11 INPUT	 
    while(DS18B20_DQ_IN&&retry<220)
	{
		retry++;
		delay_us(1);
	};
//    printf("retry:%d\r\n",retry);
	if(retry>=220)return 1;
	else retry=0;
    while(!DS18B20_DQ_IN&&retry<240)
	{
		retry++;
		delay_us(1);
	};
//    printf("retry1:%d\r\n",retry);
	if(retry>=240)return 1;	    
	return 0;
}
//从DS18B20读取一个位
//返回值：1/0
u8 DS18B20_Read_Bit(void) 	 
{
    u8 data;
	DS18B20_IO_OUT();	//SET PG11 OUTPUT
//    DS18B20_DQ_OUT=0;
	DS18B20_DQ_OUT_L;
	delay_us(1);
//    DS18B20_DQ_OUT=1;
	DS18B20_DQ_OUT_H;
	DS18B20_IO_IN();	//SET PG11 INPUT
	delay_us(12);
	if(DS18B20_DQ_IN)data=1;
    else data=0;	 
    delay_us(50);
    return data;
}
//从DS18B20读取一个字节
//返回值：读到的数据
u8 DS18B20_Read_Byte(void)     
{        
    u8 i,j,dat;
    dat=0;
	for (i=1;i<=8;i++) 
	{
//        j=DS18B20_Read_Bit();
//        dat=(j<<7)|(dat>>1);

		 j=DS18B20_Read_Bit();
        if(j)
		{
        	dat |= (1<<i); //如果读出的数据位为正
		}
		else
		{
			dat &= ~(1<<i);//如果读出的数据位为负
		}

    }
//	printf("dat=%d\r\n",dat);
    return dat;
}
//写一个字节到DS18B20
//dat：要写入的字节
void DS18B20_Write_Byte(u8 dat)     
 {             
    u8 j;
    u8 testb;
	DS18B20_IO_OUT();	//SET PG11 OUTPUT;
    for (j=1;j<=8;j++) 
	{
        testb=dat&0x01;
        dat=dat>>1;
        if (testb) 
        {
//            DS18B20_DQ_OUT=0;	// Write 1
        	DS18B20_DQ_OUT_L;
            delay_us(2);
//            DS18B20_DQ_OUT=1;
            DS18B20_DQ_OUT_H;
            delay_us(60);
        }
        else 
        {
//            DS18B20_DQ_OUT=0;	// Write 0
        	DS18B20_DQ_OUT_L;
            delay_us(60);
//            DS18B20_DQ_OUT=1;
            DS18B20_DQ_OUT_H;
            delay_us(2);                          
        }
    }
}
//开始温度转换
void DS18B20_Start(void) 
{   						               
    DS18B20_Rst();	   
	DS18B20_Check();	 
    DS18B20_Write_Byte(0xcc);	// skip rom
    DS18B20_Write_Byte(0x44);	// convert
} 

//初始化DS18B20的IO口 DQ 同时检测DS的存在
//返回1:不存在
//返回0:存在
u8 DS18B20_Init(void)
{
		GPIO_InitTypeDef GPIO_InitStruct = {0};

		  /* GPIO Ports Clock Enable */
		  __HAL_RCC_GPIOB_CLK_ENABLE();

		  /*Configure GPIO pins : PB0 */
		  GPIO_InitStruct.Pin = GPIO_PIN_15;
		  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
		  GPIO_InitStruct.Pull = GPIO_PULLUP;
		  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
		  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

		  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15, GPIO_PIN_SET);    //输出1

	DS18B20_Rst();
	printf("DS18B20_Rst\r\n");
	return DS18B20_Check();
}  
//从ds18b20得到温度值
//精度：0.1C
//返回值：温度值 （-550~1250）
short DS18B20_Get_Temp(void)
{
//    u8 temp;
    u8 TL,TH;
	short tem;
    DS18B20_Start();  			// ds1820 start convert
    DS18B20_Rst();
    DS18B20_Check();	 
    DS18B20_Write_Byte(0xcc);	// skip rom
    DS18B20_Write_Byte(0xbe);	// convert	    
    TL=DS18B20_Read_Byte(); 	// LSB   
    TH=DS18B20_Read_Byte(); 	// MSB  
	    	  
//    if(TH>7)
//    {
//        TH=~TH;
//        TL=~TL;
//        temp=0;					//温度为负
//    }else temp=1;				//温度为正
//    tem=TH; 					//获得高八位
//    tem<<=8;
//    tem+=TL;					//获得底八位
//    tem=(float)tem*0.0625;		//转换

    //M1820Z 温度计算公式。
    //小于40度的温度计算方法，反码+1 - 40
    if(TH&0x80)
    		tem=(~((TH*256)+TL)+1)/256 - 40;
    else
    		tem=((TH*256) + TL)/256 + 40;

	return tem; 		//返回温度值
}
unsigned char sensor_data_value[2];       //传感器数据
unsigned char FRACTION_INDEX[16] = {0, 1, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 7, 8, 9, 9 };//小数值查询表
void DS18B20_GetTem(void)
{
    unsigned char tem_h,tem_l;    //温度高位字节及低位字节
    unsigned char a,b;            //临时变量
    unsigned char flag;           //温度正负标记，正为0，负为1


    DS18B20_Start();  			// ds1820 start convert
	DS18B20_Rst();
	DS18B20_Check();
	DS18B20_Write_Byte(0xcc);	// skip rom
	DS18B20_Write_Byte(0xbe);	// convert
	tem_l=DS18B20_Read_Byte(); 	// LSB
	tem_h=DS18B20_Read_Byte(); 	// MSB

    /* 判断温度正负 */
    if(tem_h & 0x80)
    {
        flag = 1;                 //温度为负
        a = (tem_l>>4);           //取温度低4位原码
        b = (tem_h<<4)& 0xf0;     //取温度高4位原码
        tem_h = ~(a|b) + 1;       //取整数部分数值，不符号位

        tem_l = ~(a&0x0f) + 1;    //取小数部分原值，不含符号位
    }
    else
    {
        flag = 0;                 //为正
        a = tem_h<<4;
        a += (tem_l&0xf0)>>4;     //得到整数部分值
        b = tem_l&0x0f;           //得出小数部分值
        tem_h = a;                //整数部分
        tem_l = b&0xff;           //小数部分
    }

    sensor_data_value[0] = FRACTION_INDEX[tem_l]; //查表得小数值
    sensor_data_value[1] = tem_h| (flag<<7);      //整数部分，包括符号位

    printf("tem:%d.%d\r\n",tem_h,tem_l);
}


unsigned char ch[10];
////////////处理数据部分/////////////////
void getTemStr(void)
{
    unsigned char temh,teml;

    teml = sensor_data_value[0];
    temh = sensor_data_value[1];

//    SendString_u1("\n",1 );

    ch[0] = ' ';
    ch[1] = ' ';
    //num = teml*625;          //小数部分的取值每位代表0.0625（精度）
    if(temh & 0x80)            //判断正负温度
    {
        ch[2]='-';              //最高位为正
    }
    else ch[2]='+';
    if(temh/100==0)
        ch[3]=' ';
    else ch[3]=temh/100+0x30;      //+0x30 为变 0~9 ASCII码
    if((temh/10%10==0)&&(temh/100==0))
        ch[4]=' ';
    else ch[4]=temh/10%10+0x30;
    ch[5]=temh%10+0x30;
    ch[6]='.';
    ch[7]=teml+0x30;// 小数部分
    ch[8]='\0';
    ch[9]=' ';

   printf("temp:%s",ch);
}
